﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using GLWrap;
using GLWrap.SceneObjects;
using ReAnimation.DAL.Domain;
using ReAnimation.DAL.RepositoryInterfaces;
using ReAnimation.Domain;
using ReAnimation.Graphics;
using ReAnimation.Graphics.Handlers.TwoAtomsSelect;
using ReAnimation.Helpers.Common;
using ReAnimation.Helpers.IoC;
using ReAnimation.Helpers.WinForms;
using ReAnimation.MVP.ModelInterfaces;
using ReAnimation.MVP.Presenters;
using ReAnimation.MVP.ViewInterfaces;
using Sharp3D.Math.Core;
using ReAnimation.Graphics.Handlers;

namespace ReAnimation.MVP.Views
{
    public partial class MainForm : BaseFormView,IMainView
    {
        private const string ValueMemberName = "ValueMember";
        private const string DisplayMemberName = "DisplayMember";

        private readonly IGlSceneManager _glSceneManager;
        private readonly IMainModel _mainModel;
        private readonly IMainPresentationModel _mainPresentationModel;
        private readonly IMoleculeDrawer _moleculeDrawer;
        private readonly MainPresenter _mainFormPresenter;
        private readonly ITwoAtomsSelectHandler _twoAtomsSelectHandler;
        private readonly ILazyInject<ILinkingDialogView> _linkingDialogViewInjector;
        private readonly IZMatrixTable _zMatrixTable;
        private readonly NavigationHandler _navigationHandler;
        private readonly IAtomDescriptionRepository _atomDescriptionRepository;


        //REDO: partially move to the properties?
        public MainForm(IGlSceneManager glSceneManager,
                        IMoleculeDrawer moleculeDrawer,
                        IMainModel mainModel,
                        IMainPresentationModel mainPresentationModel,
                        ITwoAtomsSelectHandler twoAtomsSelectHandler,
                        IAtomDescriptionRepository atomDescriptionRepository,
                        ILazyInject<ILinkingDialogView> linkingDialogViewInjector,
                        IZMatrixTable zMatrixTable,
                        MainPresenter mainFormPresenter)
        {
            _zMatrixTable = zMatrixTable; 
            _glSceneManager = glSceneManager;
            _moleculeDrawer = moleculeDrawer;
            _mainModel = mainModel;
            _twoAtomsSelectHandler = twoAtomsSelectHandler;
            _mainPresentationModel = mainPresentationModel;
            _mainFormPresenter = mainFormPresenter;
            _linkingDialogViewInjector = linkingDialogViewInjector;
            _navigationHandler = new NavigationHandler(_moleculeDrawer);
            _atomDescriptionRepository = atomDescriptionRepository;

            _twoAtomsSelectHandler.MoleculeDrawer = _moleculeDrawer;

            InternalInitializeComponent();
            

            sceneOpenGLControl.InitializeContexts();

            _glSceneManager.Initialize(sceneOpenGLControl);
            InitializeMoleculeDrawer();

            var light = new Light { Position = new Vector3F(-10, 10, 10) };

            _glSceneManager.AddSceneObject(light);
            _mainModel.CurrentMoleculeChanged += CurrentMoleculeChangedHandler;
            
            _mainFormPresenter.View = this;
            _glSceneManager.Refresh();

            _mainPresentationModel.LinkingModeChanged += _mainPresentationModel_LinkingModeChanged;
            _twoAtomsSelectHandler.Selected += _twoAtomsSelectHandler_Selected;
            _mainModel.CurrentMoleculeStructureChanged += _mainModel_CurrentMoleculeStructureChanged;
            _mainModel.MoleculesCollectionChanged += MainModelOnMoleculesCollectionChanged;


            _navigationHandler.StartHandle();

        }

        private void MainModelOnMoleculesCollectionChanged(object sender, EventArgs eventArgs)
        {
            currentMoleculeComboBox.DataSource = _mainModel.Molecules;
        }

        private void InternalInitializeComponent()
        {
            InitializeComponent();
            //TODO: Think it's ok to have such code inside VIEW... but.. i feel gulty +)
            var zMatrixControl = _zMatrixTable as UserControl;
            
            zMatrixControl.Dock = DockStyle.Fill;
            zMatrixControl.Location = new System.Drawing.Point(3, 3);
            zMatrixControl.Size = new System.Drawing.Size(470, 318);
            zMatrixControl.TabIndex = 0;
           
            zMatrixTabPage.Controls.Add(zMatrixControl);
        }

        void _mainModel_CurrentMoleculeStructureChanged(object sender, EventArgs e)
        {
            _moleculeDrawer.Update();
        }

        void _twoAtomsSelectHandler_Selected(object sender, EventArg<Pair<Atom, Atom>> e)
        {
            _mainPresentationModel.CurrentlySelectedForLinkingAtoms = e.Data;
            LinkingAtomsPairSelected.Throw(this,EventArgs.Empty);
        }

        void _mainPresentationModel_LinkingModeChanged(object sender, EventArg<bool> e)
        {
            if (e.Data)
            {
                linkModeButton.Text = "End linking mode";
                _twoAtomsSelectHandler.StartHandle();
            }
            else
            {
                linkModeButton.Text = "Start linking mode";
                _twoAtomsSelectHandler.StopHandle();
            }
        }

        private void InitializeMoleculeDrawer()
        {
            _moleculeDrawer.Init(_glSceneManager);
            _moleculeDrawer.Molecule = _mainModel.CurrentMolecule;//TODO: need to be independent from sequence          
        }

        void CurrentMoleculeChangedHandler(object sender, EventArgs e)
        {
            currentMoleculeComboBox.SelectedItem = _mainModel.CurrentMolecule;
        }

        public event EventHandler LoadFromDb;
        public event EventHandler LinkingAtomsPairSelected;
        public event EventHandler CreateNewMolecule;
        public event EventHandler LoadMolecule;
        public event EventHandler CreateNewAnimation;
        public event EventHandler LoadAnimation;
        public event EventHandler SaveAnimation;

        public void RePaintMolecule()
        {
            _moleculeDrawer.Update();
            sceneOpenGLControl.Refresh();
        }

        public void ShowAtomsLinkingDialog()
        {
            ILinkingDialogView linkingDialogView = _linkingDialogViewInjector.Get();
            linkingDialogView.ShowLinkingDialog();
        }

        public void ShowNewMoleculeDialog()
        {
            throw new NotImplementedException();
        }

        private void btnLinkingMode_Click(object sender, EventArgs e)
        {
            _mainPresentationModel.LinkingMode = !_mainPresentationModel.LinkingMode;
        }

        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
     
        }

        private void sceneOpenGLControl_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {

        }

        private void newMoleculeButton_Click(object sender, EventArgs e)
        {
            CreateNewMolecule.Throw(this,EventArgs.Empty);
        }
    }
}